package com.zjxf.config.interceptor;

import com.zjxf.base.annotation.RequestLimit;
import com.zjxf.cache.CacheKeys;
import com.zjxf.exception.RequestLimitException;
import com.zjxf.redis.StringRedisService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * created with IntelliJ IDEA
 *
 * @author: create by limu
 * Date: 2020/5/22
 * Time：20:43
 */
@Slf4j
@Aspect
@Component
public class RequestLimitInterceptor {

    @Autowired
    private StringRedisService stringRedisService;

    /**
     * 接口限流
     * 调用次数
     *
     * @param limit     次数
     * @throws RequestLimitException 请求多次异常
     */
    @Before("within(@org.springframework.web.bind.annotation.RequestMapping *) && @annotation(limit)")
    public void requestLimit(RequestLimit limit) throws RequestLimitException {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String ip = request.getRemoteAddr();
            String url = request.getServletPath();
            String requestLimitKey = CacheKeys.getRequestLimitIp(url, ip);
            String ipRequestCountStr = stringRedisService.get(requestLimitKey).orElse(null);
            if (ipRequestCountStr == null) {
                ipRequestCountStr = "1_" + System.currentTimeMillis();
                stringRedisService.setContainExpire(requestLimitKey, ipRequestCountStr,10,TimeUnit.SECONDS);
            } else {
                String[] s = ipRequestCountStr.split("_");
                int count = Integer.parseInt(s[0]);

                if (count >= limit.count()) {
                    log.info("用户IP[{}], 访问地址[{}], 超过了限定的次数[{}]", ip, url, limit.count());
                    throw new RequestLimitException();
                }

                ipRequestCountStr = (count + 1) + "_" + s[1];
                long last = limit.time() - (System.currentTimeMillis() - Long.parseLong(s[1]));
                if (last > 0) {
                    stringRedisService.setContainExpire(requestLimitKey, ipRequestCountStr, limit.time(), TimeUnit.MILLISECONDS);
                }
            }

        } catch (RequestLimitException e) {
            throw e;
        } catch (Exception e) {
            log.error("发生异常", e);
        }
    }
}
